#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int count = 0;
// 初始化互斥锁
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 初始化条件变量
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;


// 期望功能是读或者写的一方 一直进行读写操作 直到缓冲读完或者写满 暂时释放锁

/// @brief 向buffer写入数据
/// @param arg 
/// @return 
void* producer(void* arg)
{
    int item = 1;
    // 使用共同的变量 使用互斥锁 首先获取锁
    pthread_mutex_lock(&mutex);
    printf("producer拿到锁了\n");
    while (1)
    {
        // // 使用共同的变量 使用互斥锁 首先获取锁
        // pthread_mutex_lock(&mutex);
        // 如果缓冲区写满 使用条件变量暂停当前线程
        if (count == BUFFER_SIZE)
        {
            // 唤醒消费者
            pthread_cond_signal(&cond);
            // 暂停线程
            pthread_cond_wait(&cond, &mutex);
        }

        // 缓冲区没有满
        buffer[count++] = item++;
        printf("在buffer中写入了%d\n", item - 1);
        // // 最后释放锁
        // pthread_mutex_unlock(&mutex);
    }
    // 最后释放锁
    pthread_mutex_unlock(&mutex);
    
}
/// @brief 从buffer读取数据
/// @param arg 
/// @return 
void* consumer(void* arg)
{
    // 使用共同的变量 使用互斥锁 首先获取锁
    pthread_mutex_lock(&mutex);
    printf("consumer拿到锁了\n");
    while (1)
    {
        // // 使用共同的变量 使用互斥锁 首先获取锁
        // pthread_mutex_lock(&mutex);
        if(count == 0)
        {
            // 缓冲区中没有消息
            // 唤醒生产者
            pthread_cond_signal(&cond); 
            // 暂停线程
            pthread_cond_wait(&cond, &mutex);
            // 通知生产者可以继续写

        }
        printf("从buffer中读取到了%d\n", buffer[--count]);

        // // 最后释放锁
        // pthread_mutex_unlock(&mutex);
    }
    // 最后释放锁
    pthread_mutex_unlock(&mutex);
}


int main(int argc, char const *argv[])
{
    // 创建两个线程 一个向buffer中写 一个从buffer中读
    pthread_t producer_thread, consumer_thread;
    // 创建生产者线程
    pthread_create(&producer_thread, NULL, producer, NULL);
    // 创建消费者线程
    pthread_create(&consumer_thread, NULL, consumer, NULL);

    // 主线程需要挂起等待两个线程完成
    pthread_join(producer_thread, NULL);
    pthread_join(consumer_thread, NULL);
    return 0;
}
